package cn.xiyun.xiyuncc.server.impl;

import cn.xiyun.xiyuncc.dto.CourseParamDto;
import cn.xiyun.xiyuncc.dto.CourseSearchDto;
import cn.xiyun.xiyuncc.mapper.HighlightResultMapper;
import cn.xiyun.xiyuncc.repository.ESRepository;
import cn.xiyun.xiyuncc.result.PageList;
import cn.xiyun.xiyuncc.server.ISearchCourseService;
import cn.xiyun.xiyuncc.vo.CourseTermVO;
import cn.xiyun.xiyuncc.vo.PageListVO;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
public class SearchCourseServiceImpl implements ISearchCourseService {
    @Autowired
    private ESRepository esRepository;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public PageList<CourseSearchDto> selectCourseSearch(CourseParamDto courseParamDto) {

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // name
        if (StringUtils.hasLength(courseParamDto.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", courseParamDto.getKeyword()));
        }
        // 收费规则(收费/免费)
        if (StringUtils.hasLength(courseParamDto.getChargeName())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("chargeName", courseParamDto.getChargeName()));
        }
        // 等级
        if (StringUtils.hasLength(courseParamDto.getGradeName())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("gradeName", courseParamDto.getGradeName()));
        }
        // 类型
        if (courseParamDto.getCourseTypeId() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("courseTypeId", courseParamDto.getCourseTypeId()));
        }

        // 查询价格范围
        if (courseParamDto.getPriceMin() != null) {
            //最大值
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(courseParamDto.getPriceMin()));
        }
        if (courseParamDto.getPriceMax() != null) {
            //最小值
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(courseParamDto.getPriceMax()));
        }
        //根据什么字段排序
        String sortName = "";
        if (courseParamDto.getSortField().equalsIgnoreCase("xp")) {
            sortName = "onlineTime";
        } else if (courseParamDto.getSortField().equalsIgnoreCase("pl")) {
            sortName = "commentCount";
        } else if (courseParamDto.getSortField().equalsIgnoreCase("jg")) {
            sortName = "price";
        } else if (courseParamDto.getSortField().equalsIgnoreCase("rq")) {
            sortName = "viewCount";
        } else {
            sortName = "saleCount";
        }
        //升序降序
        SortOrder sortOrder = courseParamDto.getSortType().equals("asc") ? SortOrder.ASC : SortOrder.DESC;
        //SortBuilders.fieldSort("")排序字段
        nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortName).order(sortOrder));
        // 分页
        nativeSearchQueryBuilder.withPageable
                (PageRequest.of((courseParamDto.getPage() - 1), courseParamDto.getRows() - 1 * courseParamDto.getPage()));

        // 查询条件赋值给nativeSearchQueryBuilder
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);


        // 关键字高亮字段与高亮颜色
        HighlightBuilder.Field highlightBuilder = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
        nativeSearchQueryBuilder.withHighlightFields(highlightBuilder);
        // 聚合条件添加
        TermsAggregationBuilder gradeNameAgg = AggregationBuilders.terms("gradeNameAgg").field("gradeName");
        TermsAggregationBuilder chargeNameAgg = AggregationBuilders.terms("chargeNameAgg").field("chargeName");
        // 将聚合条件添加给nativeSearchQueryBuilder
        nativeSearchQueryBuilder.addAggregation(chargeNameAgg).addAggregation(gradeNameAgg);
        // 查询结果
        NativeSearchQuery build = nativeSearchQueryBuilder.build();


        // 查询并处理高亮结果
        AggregatedPage<CourseSearchDto> search = elasticsearchRestTemplate.queryForPage(build, CourseSearchDto.class, highlightResultMapper);
        // 返回前端的map集合
        HashMap<String, List<CourseTermVO>> mapVO = new HashMap<>();
        // 处理聚合结果
        Map<String, Aggregation> stringAggregationMap = search.getAggregations().asMap();
        // 获取 Map中所有的key
        Set<String> strings = stringAggregationMap.keySet();
        // 遍历key的集合
        strings.forEach(key->{
            ArrayList<CourseTermVO> list = new ArrayList<>();
            // 根据 key 获取 Map 集合中的数据
            ParsedStringTerms aggregation = (ParsedStringTerms) stringAggregationMap.get(key);
            List<? extends Terms.Bucket> buckets = aggregation.getBuckets();
            // 遍历
            buckets.forEach(bucket->{
                CourseTermVO courseTermVO = new CourseTermVO(bucket.getKey().toString(),bucket.getDocCount());
                list.add(courseTermVO);
            });

            mapVO.put(key,list);
        });
        long totalElements = search.getTotalElements();
        List<CourseSearchDto> content = search.getContent();
        PageList<CourseSearchDto> pageListVO = new PageListVO(totalElements, content, mapVO);

        return pageListVO;

    }

    @Autowired
    private ElasticsearchRepository elasticsearchRepositoryFactory;

    /**
     * 课程上架存入es
     *
     * @param courseSearchDto
     */
    @Override
    public void courseSearchSave(CourseSearchDto courseSearchDto) {
        esRepository.save(courseSearchDto);
    }

    /**
     * 课程下架从es删除
     *
     * @param id
     */
    @Override
    public void courseSearchDelete(Long id) {
        esRepository.deleteById(id);
    }


}
